package com.cb2.algorithm.leetcode;

import java.util.ArrayList;
import java.util.List;

/**
 * <a href="https://leetcode.cn/problems/combination-sum-iii/">组合总和 III(Combination Sum III)</a>
 * <p>找出所有相加之和为 n 的 k 个数的组合，且满足下列条件：
 * <ul>
 *     <li>只使用数字1到9</li>
 *     <li>每个数字 最多使用一次 </li>
 * </ul>
 * </p>
 * <p>返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次，组合可以以任何顺序返回。</p>
 *
 * <p>
 * <b>示例：</b>
 * <pre>
 * 示例 1:
 *      输入: k = 3, n = 7
 *      输出: [[1,2,4]]
 *      解释:
 *          1 + 2 + 4 = 7
 *          没有其他符合的组合了。
 *
 * 示例 2:
 *      输入: k = 3, n = 9
 *      输出: [[1,2,6], [1,3,5], [2,3,4]]
 *      解释:
 *          1 + 2 + 6 = 9
 *          1 + 3 + 5 = 9
 *          2 + 3 + 4 = 9
 *          没有其他符合的组合了。
 *
 * 示例 3:
 *      输入: k = 4, n = 1
 *      输出: []
 *      解释: 不存在有效的组合。
 *          在[1,9]范围内使用4个不同的数字，我们可以得到的最小和是1+2+3+4 = 10，因为10 > 1，没有有效的组合。
 * </pre>
 * </p>
 *
 * <p>
 * <b>提示：</b>
 *  <ul>
 *      <li>2 <= k <= 9</li>
 *      <li>1 <= n <= 60</li>
 *  </ul>
 * </p>
 *
 * @author c2b
 * @see LC0039CombinationSum_M 组合总和(Combination Sum)
 * @see LC0040CombinationSum_II_M 组合总和 II(Combination Sum II)
 * @see LC0216CombinationSum_III_M 组合总和 III(Combination Sum III)
 * @see LC0377CombinationSum_IV_M 组合总和 IV(Combination Sum IV)
 * @since 2025/2/12 11:02
 */
public class LC0216CombinationSum_III_M {
    static class Solution {
        public List<List<Integer>> combinationSum3(int k, int n) {
            List<List<Integer>> resList = new ArrayList<>();
            backtracking(n, k, 1, 0, new ArrayList<>(), resList);
            //backtracking2(n, k, 1, new ArrayList<>(), resList);
            return resList;
        }

        private void backtracking(int targetSum, int k, int startIdx, int pathSum, List<Integer> path, List<List<Integer>> resList) {
            if (pathSum == targetSum && path.size() == k) {     // 终止条件
                resList.add(new ArrayList<>(path));             // 存放结果
                return;                                         // return
            }
            // 1.剩余可选数字不足 + 已选数字数量不足 k 个,后续的选取无意义
            // 2.当前路径上的数字和 >= targetSum ，后续路径和不断增加，一定大于targetSum，也无意义
            // 3.当前选取的数字数量 >= k，不符合题意
            for (int i = startIdx; i <= 9 - (k - path.size()) + 1 && pathSum < targetSum && path.size() < k; i++) {
                // 处理
                pathSum += i;
                path.add(i);
                // 递归
                backtracking(targetSum, k, i + 1, pathSum, path, resList);
                // 回溯
                pathSum -= i;
                path.remove(path.size() - 1);
            }
        }

        private void backtracking2(int targetSum, int k, int startIdx, List<Integer> path, List<List<Integer>> resList) {
            if (k == 0) {
                if (targetSum == 0) {
                    resList.add(new ArrayList<>(path));
                }
                return;
            }
            for (int i = startIdx; i <= 9; i++) {
                if (i > targetSum) {
                    return;
                }
                path.add(i);
                backtracking2(targetSum - i, k - 1, i + 1, path, resList);
                path.remove(path.size() - 1);
            }
        }
    }

    public static void main(String[] args) {
        Solution solution = new Solution();
        Printer.printListListInteger(solution.combinationSum3(3, 7));
        Printer.printListListInteger(solution.combinationSum3(3, 9));
        Printer.printListListInteger(solution.combinationSum3(4, 1));
    }
}
